Skip to content

[google_maps_flutter] Add MapColorScheme support to Android and iOS#11736

Open
snaeji wants to merge 1 commit into
flutter:mainfrom
snaeji:colorscheme-mobile-support-v2
Open

[google_maps_flutter] Add MapColorScheme support to Android and iOS#11736
snaeji wants to merge 1 commit into
flutter:mainfrom
snaeji:colorscheme-mobile-support-v2

Conversation

@snaeji

@snaeji snaeji commented May 19, 2026

Copy link
Copy Markdown

Description

Wires up MapColorScheme (light/dark/followSystem) to native APIs on Android and iOS. The platform interface and app-facing google_maps_flutter package already exposed this parameter (added in 2.16.0 for web), but the Android and iOS plugins silently ignored it.

  • Android: GoogleMap.setMapColorScheme() is invoked with the matching MapColorScheme constant. Both creation-time and runtime updates (via interpretMapConfiguration) are supported.
  • iOS: GMSMapView.overrideUserInterfaceStyle is set to UIUserInterfaceStyleLight / Dark / Unspecified — the documented API per the Google Maps SDK for iOS.

The change is mirrored across google_maps_flutter_ios, google_maps_flutter_ios_sdk9, google_maps_flutter_ios_sdk10, and google_maps_flutter_ios_shared_code via dart tool/sync_shared_files.dart.

The colorScheme doc comment in google_maps_flutter and google_maps_flutter_platform_interface is updated to reflect the new platform support (previously documented as "Web only").

Tests added:

  • Android: Convert.toMapColorScheme JUnit tests for all three enum values; interpretMapConfiguration_handlesColorScheme dispatcher test mirroring _handlesStyle; Dart-side creation-params test asserting colorScheme flows through to the platform view.
  • iOS: Parametrized Dart-side creation-params tests covering light, dark, followSystem, and null; matching tests propagated to sdk9 and sdk10 via the shared-code sync.

Fixes flutter/flutter#186737

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2

@google-cla

google-cla Bot commented May 19, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@snaeji snaeji force-pushed the colorscheme-mobile-support-v2 branch from 4da8e36 to 23d6cae Compare May 19, 2026 11:29
@snaeji snaeji marked this pull request as ready for review May 19, 2026 11:36

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements colorScheme support for cloud-based maps styling brightness on Android and iOS, extending the existing web functionality. The updates span the platform interface, native platform implementations, and Pigeon message definitions. A review comment correctly identifies that the documentation for colorScheme should be updated to reflect that it can be modified after map creation on iOS, aligning the documentation with the new implementation.

Comment thread packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart Outdated
@snaeji snaeji force-pushed the colorscheme-mobile-support-v2 branch from 23d6cae to 1d4d137 Compare May 19, 2026 12:34
@stuartmorgan-g stuartmorgan-g added triage-ios Should be looked at in iOS triage triage-android Should be looked at in Android triage labels May 19, 2026

@LongCatIsLooong LongCatIsLooong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return PlatformMapColorScheme.followSystem;
}

// The enum comes from a different package, which could get a new value at

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe switch expressions / statements have to be exhaustive or it is gong to be a compile time error. The code isn't going to compile if there's an unhandled case. IOW the runtime error will never be reachable, unless you add a default case. But adding a new case to an existing enum should require a major version bump I think? So we don't really have to handle that at runtime.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this could just be an expression:

return switch (colorScheme) { 
  null => null,
  .light => .light,
  .dart => .dart,
  .followSystem => .followSystem,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, why do we need 2 enums that represent the same thing? Can we just re-export one / making one of the an alias of the other? Then we don't need this since there's only one type under the hood.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe switch expressions / statements have to be exhaustive or it is gong to be a compile time error.

Switch expressions do, not arbitrary switch statements.

But adding a new case to an existing enum should require a major version bump I think?

We have not traditionally considered that to be a major version change. We may need to revisit that at some point as switch expressions become more common, but for now we don't (at least for platform interfaces).

So we don't really have to handle that at runtime.

We do, for the specific goal of not requiring breaking the platform interface all the time.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, why do we need 2 enums that represent the same thing?

Because Pigeon definitions currently aren't allowed to import things from other files. And doing so in the case of an enum from another package would be extremely dangerous since it would allow for Dart code to change without the native side changing.

@snaeji snaeji May 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks both!

_platformMapColorSchemeFromMapColorScheme
The structure here mirrors _platformMarkerTypeFromMarkerType immediately above (line 1360).

I gather from the discussion above that the alternatives suggested (switch expression / collapsing the two enums) wouldn't fit here — the runtime fallback is intentional so new platform-interface enum values don't force a breaking change, and the Pigeon enum has to stay separate since Pigeon definitions can't import across files.

If there is something needed on my part or some restructuring needed please let me know.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe switch expressions / statements have to be exhaustive or it is gong to be a compile time error.

Switch expressions do, not arbitrary switch statements.

It turns out I was wrong here; some switch statements do have to be exhaustive now, including enums. The behavior changed from warning to error for enums several years ago and I'd never hit it, so we'll need to audit all the plugins for this construction and adjust it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is something needed on my part or some restructuring needed please let me know.

Given what I found and described in the comment above, this should become a default case (with the ignore updated accordingly, and the part of the comment about not using default removed) so that it works as intended.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — switched to a default: case with the same ignore, and dropped the "deliberately outside the switch" note. Synced across all four iOS packages.

}
}

static int toMapColorScheme(@NonNull PlatformMapColorScheme colorScheme) {

@reidbaker reidbaker May 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method handle unknown. What do you want the unknown behavior to be an why.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just followed patterns that are already established in the code so I am pretty confident about this.

// Line 370
static int toMapType(@NonNull PlatformMapType type) {
  return switch (type) {
    case NONE -> MAP_TYPE_NONE;
    case NORMAL -> MAP_TYPE_NORMAL;
    case SATELLITE -> MAP_TYPE_SATELLITE;
    case TERRAIN -> MAP_TYPE_TERRAIN;
    case HYBRID -> MAP_TYPE_HYBRID;
  };
}

// Line 388
static MapsInitializer.Renderer toMapRendererType(@Nullable PlatformRendererType type) {
  // null-check, then…
  return switch (type) {
    case LATEST -> MapsInitializer.Renderer.LATEST;
    case LEGACY -> MapsInitializer.Renderer.LEGACY;
  };
}

}

@Test
public void toMapColorScheme_light() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of tests that verify the 3 conversions I think the tests should be higher value like looping over all of one type and making sure there is a value that is of the appropriate other type. Handling unknown values etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I replaced the tests with a single loop over PlatformMapColorScheme.values(). The expected mapping is defined via an exhaustive switch expression, so a new enum value forces a compile error in both the production conversion and this test.

@reidbaker reidbaker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments added but directionally the android code looks ok

@snaeji snaeji force-pushed the colorscheme-mobile-support-v2 branch from 900a4f4 to df24808 Compare May 28, 2026 16:59
@snaeji

snaeji commented May 28, 2026

Copy link
Copy Markdown
Author

Force-pushed to drop a Co-Authored-By trailer that was failing the Google CLA check. Diff is identical — only the commit message changed.

@vashworth vashworth removed the triage-ios Should be looked at in iOS triage label May 28, 2026
@snaeji

snaeji commented Jun 8, 2026

Copy link
Copy Markdown
Author

@stuartmorgan-g rebased on main to clear the conflicts, no behavior changes. I believe the open threads are addressed and it's ready to land when you are. Or let me know if there is something outstanding work on my end 🙏

@camsim99 camsim99 requested a review from reidbaker June 9, 2026 18:55
@camsim99 camsim99 removed the triage-android Should be looked at in Android triage label Jun 9, 2026
return switch (colorScheme) {
MapColorScheme.light => PlatformMapColorScheme.light,
MapColorScheme.dark => PlatformMapColorScheme.dark,
MapColorScheme.followSystem => PlatformMapColorScheme.followSystem,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a default case (with an ignore to suppress the analyzer warnings, and a comment similar to what's on like 1214, minus the part about not using default) to avoid potential future breakage (per this thread).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added the default: case with // ignore: no_default_cases, unreachable_switch_default and a comment matching _platformMapTypeFromMapType (~line 1214), minus the part about not using default.

@@ -1,3 +1,7 @@
## 2.19.13

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally consider new functionality to be a minor version bump.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumped to a minor version, 2.20.0.

return PlatformMapColorScheme.followSystem;
}

// The enum comes from a different package, which could get a new value at

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is something needed on my part or some restructuring needed please let me know.

Given what I found and described in the comment above, this should become a default case (with the ignore updated accordingly, and the part of the comment about not using default removed) so that it works as intended.

@@ -1,3 +1,7 @@
## 2.18.4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same versioning note for the iOS packages.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumped the iOS packages to minor — ios/sdk9/sdk10 are all 2.19.0.

@snaeji snaeji force-pushed the colorscheme-mobile-support-v2 branch from e905762 to 7c7a7f4 Compare June 24, 2026 11:20
@snaeji snaeji requested a review from stuartmorgan-g June 24, 2026 11:46
@snaeji

snaeji commented Jun 24, 2026

Copy link
Copy Markdown
Author

Rebased onto main — single clean commit now, and the conflict is cleared. All the review points are addressed (replied inline on each thread):

  • default: case on both the Android and iOS converters, with the ignore updated and the "not using default" note removed.
  • Minor version bumps for the new functionality — google_maps_flutter_android 2.20.0, google_maps_flutter_ios / _sdk9 / _sdk10 2.19.0.
  • Added a native testSetMapColorScheme covering the iOS color-scheme path (light/dark/followSystem + the nil-unchanged case).

One thing worth flagging since it wasn't in the threads: the platform-interface and app-facing changes are doc-comment only, so I left google_maps_flutter_platform_interface under the existing ## NEXT (no version bump) and gave google_maps_flutter a 2.17.2 patch.

Verified locally before pushing: flutter analyze and dart format clean across all packages, Dart unit tests pass, and the new iOS XCTest passes on a simulator. Ready for another look — thanks!

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator

the platform-interface and app-facing changes are doc-comment only, so I left google_maps_flutter_platform_interface under the existing ## NEXT (no version bump)

Could you point me to what part of the docs linked from the PR checklist item gave the impression that doc comments were a documented exemption to our versioning policy?

Wires MapColorScheme (light/dark/followSystem) through to the native
APIs on Android and iOS. The platform interface and app-facing package
already exposed colorScheme (added in 2.16.0 for web), but the Android
and iOS implementations ignored it.

* Android: calls GoogleMap.setMapColorScheme() with the matching
  MapColorScheme constant, both at creation and on runtime configuration
  updates.
* iOS: sets GMSMapView.overrideUserInterfaceStyle to light/dark/
  unspecified, the documented Google Maps SDK for iOS approach.

The iOS change is mirrored across google_maps_flutter_ios,
google_maps_flutter_ios_sdk9, google_maps_flutter_ios_sdk10, and
google_maps_flutter_ios_shared_code via tool/sync_shared_files.dart. The
colorScheme doc comments in google_maps_flutter and
google_maps_flutter_platform_interface are updated to reflect the new
platform support.

Adds Convert and dispatcher tests plus Dart creation-params tests on
Android, parametrized creation-params tests on iOS, and a native
FGMGoogleMapController test exercising the runtime color scheme update.

Fixes flutter/flutter#186737
@snaeji snaeji force-pushed the colorscheme-mobile-support-v2 branch from 7c7a7f4 to 233ffe6 Compare June 26, 2026 15:29
@snaeji

snaeji commented Jun 26, 2026

Copy link
Copy Markdown
Author

Nothing — I relied too heavily on an LLM that pushed for this and didn't verify it myself. Note taken — bumped it to 2.15.1.

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator

I relied too heavily on an LLM that pushed for this and didn't verify it myself

Please take a few minutes to re-read the AI contribution guidelines that you agreed to in the PR checklist.

@stuartmorgan-g stuartmorgan-g left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remaining comment is just about the iOS tests, so you can create the sub-PR to land the platform interface change now in parallel with updating the test.

XCTAssertNil(error);
XCTAssertEqual(mapView.overrideUserInterfaceStyle, UIUserInterfaceStyleLight);

// Dark.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Four distinct tests should be four distinct test functions, not a constant cycle of setup/assert/setup/assert in a single test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[google_maps_flutter] colorScheme not wired up on Android and iOS

6 participants